#pragma once
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <functional>
#include "ThreadPool.hpp"
#include "InetAddr.hpp"

static const int gsock = -1;
static const int gport = -1;

using task_t = std::function<void()>;

class UdpServer
{
public:
    UdpServer(int port = gport)
        : _port(port), _sock(gsock)
    {
    }

    // 1.套接字
    //  Init的任务就是创建服务器套接字，并且绑定端口+ip
    void Init()
    {
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            std::cout << "创建套接字失败!" << std::endl;
            exit(-1);
        }
        std::cout << "创建套接字成功:" << _sock << std::endl;

        // 2.绑定端口
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY; // 任意地址

        // 填充完毕了，写到内核里
        int n = ::bind(_sock, (struct sockaddr *)&local, sizeof(local));
        if (n != 0)
        {
            std::cout << "绑定失败!" << std::endl;
            exit(-2);
        }
        std::cout << "绑定成功,端口号:" << _port << std::endl;

        // 创建线程池
        ThreadPool<task_t>::GetInstance()->Start();
    }

    void AddUser(const InetAddr &addr)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        for (auto &user : _online_user)
        {
            if (user == addr)
                return;
        }
        _online_user.push_back(addr);
    }

    // 设置一个回调函数，供线程池去执行任务
    void Sender(int sock, const std::string &message)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        for (auto &user : _online_user)
        {
            std::cout<<"向 "<<user.Debug()<<" 发送消息"<<std::endl;
            sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&user._addr, sizeof(user._addr));
        }
        return;
    }
    // 服务器启动
    void Start()
    {
        char buffer[1024];
        while (true)
        {
            // 存放client的信息
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);

            if (n > 0)
            {
                InetAddr addr(peer);
                AddUser(addr);
                std::cout << "获取新连接" << std::endl;
                std::cout<<"当前在线列表:";
                for(auto& user:_online_user){
                    std::cout<<user.Debug()<<" ";
                }
                std::cout<<std::endl;
                buffer[n] = 0;
                std::cout <<addr.Debug() <<"say:" << buffer << std::endl;
                // 将消息发送回去
                // const char *msg = "hello client!";
                // std::string ret;
                // int m = sendto(_sock, ret.c_str(), ret.size(), 0, (struct sockaddr *)&peer, len);
                auto task = std::bind(&UdpServer::Sender, this, _sock, buffer);
                ThreadPool<task_t>::GetInstance()->Push(task);
                // if (m > 0)
                // {
                //     std::cout << "sned to client success!!" << std::endl;
                // }
            }
        }
    }

    ~UdpServer()
    {
        close(_sock);
    }

private:
    int _port;
    int _sock;

    std::vector<InetAddr> _online_user;
    std::mutex _mutex;
};
